/*
 * OREKIT-X
 * Copyright 2002-2008 CS Communication & Systemes
 * 
 * Parts of this software package have been licensed to CS
 * Communication & Systemes (CS) under one or more contributor license
 * agreements.  See the NOTICE file distributed with this work for
 * additional information.
 *  
 * This is an experimental copy of OREKIT from www.orekit.org.
 * Please use the original OREKIT from orekit.org for normal work
 * unrelated to this research project.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You
 * may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.  See the License for the specific language governing
 * permissions and limitations under the License.
 */
package ore.attitudes;

import ore.Attitude;
import ore.CelestialBody;
import ore.Frame;
import ore.PositionVelocity;
import ore.errors.OrekitException;
import ore.time.AbsoluteDate;

import org.apache.commons.math.geometry.Rotation;
import org.apache.commons.math.geometry.Vector3D;

/**
 * Yaw steering is mainly used for low Earth orbiting satellites with
 * no missions-related constraints on yaw angle. It sets the yaw angle
 * in such a way the solar arrays have maximal lightning without
 * changing the roll and pitch.
 * 
 * The motion in yaw is smooth when the Sun is far from the orbital
 * plane, but gets more and more <i>square like</i> as the Sun gets
 * closer to the orbital plane. The degenerate extreme case with the
 * Sun in the orbital plane leads to a yaw angle switching between two
 * steady states, with instantaneaous &pi; radians rotations at each
 * switch, two times per orbit.  This degenerate case is clearly not
 * operationally sound so another pointing mode is chosen when Sun
 * comes closer than some predefined threshold to the orbital plane.
 * 
 * This class can handle (for now) only a theoretically perfect yaw
 * steering (i.e. the yaw angle is exactly the optimal
 * angle). Smoothed yaw steering with a few sine waves approaching the
 * optimal angle will be added in the future if needed.
 * 
 * This attitude is implemented as a wrapper on top of an underlying
 * ground pointing law that defines the roll and pitch angles.
 * 
 * Instances of this class are immutable.
 * 
 * @author Luc Maisonobe
 */
public class YawSteering
    extends GroundPointingCompensating
{

    /** 
     * Sun motion model.
     */
    private final CelestialBody sun;
    /**
     * Satellite axis that must be roughly in Sun direction.
     */
    private final Vector3D phasingAxis;


    /** 
     * @param groundPointingLaw Ground pointing attitude law without
     * yaw compensation
     * @param sun Sun motion model
     * @param phasingAxis Satellite axis that must be roughly in Sun
     * direction (if solar arrays rotation axis is Y, then this axis
     * should be either +X or -X)
     */
    public YawSteering(GroundPointing groundPointingLaw, CelestialBody sun, Vector3D phasingAxis){
        super(groundPointingLaw);
        this.sun = sun;
        this.phasingAxis = phasingAxis;
    }


    /** 
     * Compute the system yaw compensation rotation at given date.
     * 
     * @param date Date when the system state shall be computed
     * @param pv Satellite position-velocity vector at given date in given frame.
     * @param base Base satellite attitude in given frame.
     * @param frame The frame in which satellite position-velocity an attitude are given.
     * 
     * @return Yaw compensation rotation at date, i.e rotation between non compensated
     * attitude state and compensated state.
     * 
     * @throws OrekitException if some specific error occurs
     */
    public Rotation getCompensation(AbsoluteDate date, PositionVelocity pv, Attitude base, Frame frame)
        throws OrekitException
    {
        /*
         * Compensation rotation definition :
         *   Z satellite axis is unchanged;
         *   Phasing axis shall be aligned to sun direction.
         */
        Vector3D sunDirection =
            sun.getPositionVelocity(date, frame).getPosition().subtract(pv.getPosition());

        return new Rotation(Vector3D.PLUS_K, 
                            base.getRotation().applyTo(sunDirection),
                            Vector3D.PLUS_K, 
                            phasingAxis);
    }

}
